package com.test.platform.module.perf.service;

import com.test.common.component.RedisComponent;
import com.test.common.entity.perf.*;
import com.test.common.entity.system.PermissionImpl;
import com.test.common.entity.system.User;
import com.test.common.enums.system.PermissionLevelEnum;
import com.test.common.enums.system.PermissionTargetEnum;
import com.test.common.form.perf.TaskCreateForm;
import com.test.common.form.perf.TaskExecFrom;
import com.test.common.form.perf.TaskScriptForm;
import com.test.common.form.perf.TaskSearchForm;
import com.test.common.repository.perf.*;
import com.test.common.response.BizException;
import com.test.common.utils.SystemUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.Permission;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.*;

@Slf4j
@Service
public class PerfTaskService {

    @Resource
    private RedisComponent redisComponent;

    @Resource
    private PerfTaskRepository perfTaskRepository;

    @Resource
    private PerfScriptRepository perfScriptRepository;

    @Resource
    private PerfReportRepository perfReportRepository;

    @Resource
    private PerfTaskScriptRepository perfTaskScriptRepository;

    @Resource
    private PerfAgentRepository perfAgentRepository;

    @Resource
    private RedisComponent redisCommonUtil;

    @Resource
    private PerfReportService perfReportService;

    @Transactional(rollbackOn = {Exception.class})
    public PerfTaskEntity create(TaskCreateForm taskCreateForm) {
        PerfTaskEntity perfTaskEntity = new PerfTaskEntity(taskCreateForm.getTaskName(), taskCreateForm.getDescription(), SystemUtils.getUser().getName(), taskCreateForm.getRampTime(), taskCreateForm.getDuration());
        PerfTaskEntity save = perfTaskRepository.save(perfTaskEntity);

        List<TaskScriptForm> scriptForms = taskCreateForm.getScripts();
        // 去重
        HashSet<Integer> hash = new HashSet<>();
        for (TaskScriptForm script : scriptForms) {
            if (hash.contains(script.getScriptId())) {
                log.warn("重复的脚本ID，过滤掉：{}", script.getScriptId());
            } else {
                hash.add(script.getScriptId());

                // 先判断一下脚本存不存在
                Optional<PerfScriptEntity> optional = perfScriptRepository.findById(script.getScriptId());
                if (optional.isPresent()) {
                    perfTaskScriptRepository.save(new PerfTaskScriptEntity(save.getId(), script.getScriptId(), script.getUsers(), script.getQps()));
                } else {
                    throw new BizException("不存在的脚本ID：" + script.getScriptId());
                }
            }
        }

        return save;
    }


    public PerfTaskEntity modify(TaskCreateForm taskCreateForm) {

        Optional<PerfTaskEntity> optionalPerfTaskEntity = perfTaskRepository.findById(taskCreateForm.getTaskId());
        if (optionalPerfTaskEntity.isPresent()) {
            PerfTaskEntity perfTaskEntity = optionalPerfTaskEntity.get();

            if (StringUtils.isNotEmpty(taskCreateForm.getTaskName()))
                perfTaskEntity.setName(taskCreateForm.getTaskName());
            if (StringUtils.isNotEmpty(taskCreateForm.getDescription()))
                perfTaskEntity.setDescription(taskCreateForm.getDescription());
            if (taskCreateForm.getRampTime() > 0) perfTaskEntity.setRampTime(taskCreateForm.getRampTime());
            if (taskCreateForm.getDuration() > 0) perfTaskEntity.setDuration(taskCreateForm.getDuration());

            perfTaskEntity.setModifyTime(new Date());
            return perfTaskRepository.save(perfTaskEntity);
        } else {
            throw new BizException("不存在的任务ID：" + taskCreateForm.getTaskId());
        }
    }

    @Transactional(rollbackOn = {Exception.class})
    public String addScripts(ArrayList<TaskScriptForm> taskScriptFormList) {

        for (TaskScriptForm taskScriptForm : taskScriptFormList) {
            Optional<PerfTaskEntity> optionalPerfTaskEntity = perfTaskRepository.findById(taskScriptForm.getTaskId());
            if (optionalPerfTaskEntity.isPresent()) {
                perfTaskScriptRepository.save(new PerfTaskScriptEntity(taskScriptForm.getTaskId(), taskScriptForm.getScriptId(), taskScriptForm.getUsers(), taskScriptForm.getQps()));
            } else {
                throw new BizException("不存在的任务ID：" + taskScriptForm.getTaskId());
            }
        }

        return "success";
    }

    @Transactional(rollbackOn = {Exception.class})
    public String removeScripts(int taskId, int[] scriptIds) {
        for (int scriptId : scriptIds) {
            perfTaskScriptRepository.deleteByTaskIdAndScriptId(taskId, scriptId);
        }
        return "success";
    }

    public String execScript(TaskExecFrom taskExecFrom) {

        List<PerfReportEntity> perfReportEntityList = new ArrayList<>();

        List<PerfAgentEntity> agentEntityList = new ArrayList<>();
        int[] agentIds = taskExecFrom.getAgentIds();
        for (int agentId : agentIds) {
            Optional<PerfAgentEntity> agentEntityOptional = perfAgentRepository.findById(agentId);
            if (agentEntityOptional.isPresent()) {
                agentEntityList.add(agentEntityOptional.get());
            } else {
                throw new BizException("找不到执行机信息：" + agentId);
            }
        }

        Optional<PerfTaskEntity> optionalPerfTaskEntity = perfTaskRepository.findById(taskExecFrom.getTaskId());
        if (optionalPerfTaskEntity.isPresent()) {
            for (int scriptId : taskExecFrom.getScriptIds()) {
                Optional<PerfTaskScriptEntity> taskScriptEntityOptional = perfTaskScriptRepository.findByTaskIdAndScriptId(taskExecFrom.getTaskId(), scriptId);
                Optional<PerfScriptEntity> scriptEntityOptional = perfScriptRepository.findById(scriptId);
                if (taskScriptEntityOptional.isPresent() && scriptEntityOptional.isPresent()) {
                    perfReportEntityList.add(
                            new PerfReportEntity(taskExecFrom.getTaskId(),
                                    optionalPerfTaskEntity.get().getName(),
                                    scriptId,
                                    scriptEntityOptional.get().getName(),
                                    optionalPerfTaskEntity.get().getRampTime(),
                                    optionalPerfTaskEntity.get().getDuration(),
                                    new Date(taskExecFrom.getTiming()),
                                    taskScriptEntityOptional.get().getQps(),
                                    taskScriptEntityOptional.get().getUsers(),
                                    taskScriptEntityOptional.get().getRemark(),
                                    agentEntityList)
                    );

                } else {
                    throw new BizException("不存在的脚本ID：" + scriptId);
                }
            }
        } else {
            throw new BizException("不存在的任务ID：" + taskExecFrom.getTaskId());
        }

        for (PerfReportEntity perfReportEntity : perfReportEntityList) {
            perfReportRepository.save(perfReportEntity);
        }

        // 直接扫描一次
        perfReportService.scanner();

        return "任务执行成功，请进入报告列表查看";
    }

    public Page<PerfReportEntity> findReports(int taskId, int page, int size) {
        page = page - 1;
        Optional<PerfTaskEntity> optionalPerfTaskEntity = perfTaskRepository.findById(taskId);

        if (optionalPerfTaskEntity.isPresent()) {
            return perfReportRepository.findAllByTaskId(taskId, PageRequest.of(page, size, Sort.by("id").descending()));
        } else {
            throw new BizException("不存在的任务ID：" + taskId);
        }
    }

    public Page<PerfReportEntity> findScriptReports(int taskId, int scriptId, int page, int size) {
        page = page - 1;
        Optional<PerfTaskEntity> optionalPerfTaskEntity = perfTaskRepository.findById(taskId);

        if (optionalPerfTaskEntity.isPresent()) {
            return perfReportRepository.findAllByTaskIdAndScriptId(taskId, scriptId, PageRequest.of(page, size, Sort.by("id").descending()));
        } else {
            throw new BizException("不存在的任务ID：" + taskId);
        }
    }

    public Object search(TaskSearchForm taskSearchForm) {

        log.info("查询任务列表：{}", taskSearchForm);

        // admin用户可以查询到所有
        User user = (User) SecurityUtils.getSubject().getPrincipal();

        // 根据id查询，只可能查到一个
        if (taskSearchForm.getTaskId() > 0) {
            Optional<PerfTaskEntity> perfTaskEntityOptional = perfTaskRepository.findById(taskSearchForm.getTaskId());
            if (perfTaskEntityOptional.isPresent() &&
                    (user.getName().equals("admin") || SecurityUtils.getSubject().isPermitted(new PermissionImpl(perfTaskEntityOptional.get().getId(), PermissionTargetEnum.PERF_TASK, PermissionLevelEnum.READ)))
            ) {
                return perfTaskEntityOptional.get();
            } else {
                throw new BizException("没有查询到任何数据");
            }
        }

        PageRequest pageRequest = PageRequest.of(taskSearchForm.getPageNo() - 1, taskSearchForm.getPageSize(), new Sort(Sort.Direction.DESC, "modifyTime"));
        Page<PerfTaskEntity> resPage;

        // admin可以查询所有
        if ("admin".equals(user.getName())) {
            switch (taskSearchForm.type()) {
                case 0:
                    resPage = perfTaskRepository.findAll(pageRequest);
                    break;
                case 1:
                    resPage = perfTaskRepository.findAllByCreator(taskSearchForm.getCreator(), pageRequest);
                    break;
                case 2:
                    resPage = perfTaskRepository.findAllByNameContains(taskSearchForm.getTaskName(), pageRequest);
                    break;
                default:
                    resPage = perfTaskRepository.findAllByNameContainsAndCreator(taskSearchForm.getTaskName(), taskSearchForm.getCreator(), pageRequest);
                    break;
            }
        } else {
            // 添加权限列表
            List<Integer> idList = new ArrayList<>();

            if (user.getPermissionsAll() == null) {
                redisCommonUtil.delete("shiro:user:" + user.getId());
                throw new BizException("用户没有任何权限任务，请创建测试任务");
            }

            for (Permission permission : user.getPermissionsAll()) {
                PermissionImpl permission1 = (PermissionImpl) permission;
                if (permission1.getTargetType().equals(PermissionTargetEnum.PERF_TASK)) {
                    idList.add(permission1.getTargetId());
                }
            }
            // 根据权限列表查询数据
            switch (taskSearchForm.type()) {
                case 0:
                    resPage = perfTaskRepository.findAllByIdIn(idList, pageRequest);
                    break;
                case 1:
                    resPage = perfTaskRepository.findAllByIdInAndCreator(idList, taskSearchForm.getCreator(), pageRequest);
                    break;
                case 2:
                    resPage = perfTaskRepository.findAllByIdInAndNameContains(idList, taskSearchForm.getTaskName(), pageRequest);
                    break;
                default:
                    resPage = perfTaskRepository.findAllByIdInAndNameContainsAndCreator(idList, taskSearchForm.getTaskName(), taskSearchForm.getCreator(), pageRequest);
                    break;
            }
        }

        if (resPage != null && resPage.getSize() > 0) {
            return resPage;
        } else {
            throw new BizException("没有查询到任何数据");
        }
    }

    public Object getScripts(int taskId) {
        List<PerfTaskScriptEntity> perfTaskScriptEntityList = perfTaskScriptRepository.findAllByTaskId(taskId);

        Iterator<PerfTaskScriptEntity> iterator = perfTaskScriptEntityList.iterator();
        while (iterator.hasNext()) {
            PerfTaskScriptEntity perfTaskScriptEntity = iterator.next();
            // 设置脚本名称
            Optional<PerfScriptEntity> perfScriptEntityOptional = perfScriptRepository.findById(perfTaskScriptEntity.getScriptId());
            if (perfScriptEntityOptional.isPresent()) {
                perfTaskScriptEntity.setScriptName(perfScriptEntityOptional.get().getName());
                perfTaskScriptEntity.setPlatform(perfScriptEntityOptional.get().getPlatform());
                // 设置资源文件名称
                List<PerfResourceEntity> resources = perfScriptEntityOptional.get().getResources();
                for (PerfResourceEntity resource : resources) {
                    perfTaskScriptEntity.getResourceNames().add(resource.getName());
                    perfTaskScriptEntity.getResourceIds().add(resource.getId());
                }

            } else {
                log.error("找不到任务脚本文件：{} - {}", taskId, perfTaskScriptEntity.getScriptId());
                // 找不到的文件直接删掉
                iterator.remove();
            }
        }

        return perfTaskScriptEntityList;
    }

    @Transactional
    public Object updateScriptUsersOrQps(int taskId, int scriptId, String key, int value) {
        Optional<PerfTaskScriptEntity> perfTaskScriptEntityOptional = perfTaskScriptRepository.findByTaskIdAndScriptId(taskId, scriptId);
        if (perfTaskScriptEntityOptional.isPresent()) {
            PerfTaskScriptEntity perfTaskScriptEntity = perfTaskScriptEntityOptional.get();
            if (key.equals("users")) {
                perfTaskScriptEntity.setUsers(value);
            } else if (key.equals("qps")) {
                perfTaskScriptEntity.setQps(value);
            } else {
                throw new BizException("不支持的参数：" + key);
            }
            return "成功";
        } else {
            throw new BizException("找不到任务脚本对象");
        }
    }
}
